/**
 * Server-side application layer.
 *
 * @author Timothy Flynn (trflynn@wpi.edu)
 * @modified by JTM 2012/04/11
 *
 * @version April 12, 2012
 */
#include <queue>
#include <pthread.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using std::queue;
using std::cout;
using std::cerr;
using std::endl;

#include "common.h"
#include "Packet.h"
#include "Frame.h"
#include "DataLinkLayer.h"
#include "PhysicalLayer.h"
#include "ApplicationLayer.h"

// Queues to store frames/packets for inter-level comm
queue<Packet *> sendPktQ, recvPktQ;
queue<Frame *> sendFrameQ, recvFrameQ;

// Semaphores to protect access to queues
pthread_mutex_t sendPktM, recvPktM;
pthread_mutex_t sendFrameM, recvFrameM;

int main(int argc, char **argv) {
	cout << "Starting mininet Tunnel Server" << endl;
	pthread_mutex_init(&sendPktM, NULL);
	pthread_mutex_init(&recvPktM, NULL);
	pthread_mutex_init(&sendFrameM, NULL);
	pthread_mutex_init(&recvFrameM, NULL);

	PhysicalLayer *phys = new PhysicalLayer(0.05f);
	DataLinkLayer *data = new DataLinkLayer();
//	ApplicationLayer *app = new ApplicationLayer(true);

	// Launch DL and PL threads
	pthread_t pt, dt;
	pthread_create(&dt, NULL, runDataLinkLayer, data);
	pthread_create(&pt, NULL, runPhysicalLayer, phys);

	// @modified by JTM 2012/04/11
//	app->run();
	while(1) {
		if(pthread_mutex_trylock(&recvPktM) == 0) {
			Packet *p = NULL;

			if(!recvPktQ.empty()) {
				p = recvPktQ.front();
				recvPktQ.pop();
				cout << "Server: Got packet! " << p->data << endl;
			}
			pthread_mutex_unlock(&recvPktM);

			if(p != NULL) {
				Packet *p2 = new Packet();
				p2->end = true;
				p2->seq = INC(p->seq);
				p2->length = 14;
				p2->data = (char *)malloc((p2->length+1) * sizeof(char));
				memcpy(p2->data, "WHADDUP~CLIENT", p2->length);
				p2->data[p2->length] = '\0';

				pthread_mutex_lock(&sendPktM);
				sendPktQ.push(p2);
				pthread_mutex_unlock(&sendPktM);
			}
		}
	}

	return 0;
}
